package site.jlopen.secret.client;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import site.jlopen.secret.common.SecretClientResponse;
import site.jlopen.secret.common.SecretReqBaseForm;
import site.jlopen.secret.config.SecretClientProperties;
import site.jlopen.secret.service.intf.SecretAuthService;

/**
* @ClassName: SecretClientRequest
* @Description: 客户端请求工具
* @author ChenJiaLu
* @date 2024年9月26日 下午5:55:41
* @param <T>
 */
public class SecretClientHttp<T> {
	private final Logger logger = LoggerFactory.getLogger(getClass());

	private final SecretClientProperties clientProperties;
	
	private int retryLoginCount = 0;
	
	private final static int RETRYLOGINSIZE = 10;
	
	public SecretClientHttp(SecretClientProperties clientProperties) {
		this.clientProperties = clientProperties;
	}

	public <O extends SecretReqBaseForm<Object>> SecretClientResponse<T> execute(String url , Object obj) {
		return execute(url , obj, new TypeReference<SecretClientResponse<T>>() {});
	}
	
	@SuppressWarnings("unchecked")
	public <O extends SecretReqBaseForm<Object>> SecretClientResponse<T> execute(String url , Object obj, TypeReference<SecretClientResponse<T>> typeReference) {
        if(!url.equals(SecretReqUrl.AUTH_URL) && null == clientProperties.getToken()) {
        	return new SecretClientResponse<T>(SecretClientHttpErrorCode.NOT_LOGIN_ERROR, "SDK未获取token");
        }
		String json = JSONUtil.toJsonStr(obj);
        try {
        	HttpRequest request = HttpRequest.post(clientProperties.getHost() +  url)
                    .setConnectionTimeout(clientProperties.getTimeout())
                    .addHeaders(getHeaderMap(json))
                    ;
        	if(obj instanceof Map) {
        		request.form((Map<String, Object>) obj);
            }else {
            	request.body(json);
            }
        	HttpResponse response = request.execute();
        	String result = response.body();
            logger.info("请求地址：{}{}：{}→响应结果：{}", clientProperties.getHost(),  url, json, result);
			if(null == typeReference) {
				typeReference = new TypeReference<SecretClientResponse<T>>() {};
			}
            SecretClientResponse<T> bean = JSONUtil.toBean(result, typeReference, false);
            if(bean.getStatus() == SecretClientHttpErrorCode.NOT_LOGIN_ERROR) {
            	if(retryLoginCount <= RETRYLOGINSIZE) {
    				logger.info("secret sdk 请求失效，开始第{}次重试:{}", retryLoginCount + 1, bean);
    				login(url, obj, typeReference);
    				retryLoginCount ++;
    			}else {
    				logger.error("secret sdk 尝试重试登录，{}次后失败了:{}", RETRYLOGINSIZE, bean);
    			}
            }
            return bean;
		} catch (HttpException e) {
	        logger.error("请求地址：{}{}→发生异常：{}", clientProperties.getHost(),  url, e);
			return new SecretClientResponse<T>(SecretClientHttpErrorCode.OPERATION_ERROR, e.getMessage());
		} catch (IORuntimeException e) {
	        logger.error("请求地址：{}{}→发生异常：{}", clientProperties.getHost(),  url, e);
			return new SecretClientResponse<T>(SecretClientHttpErrorCode.OPERATION_ERROR, e.getMessage());
		} catch (Exception e) {
	        logger.error("请求地址：{}{}→发生异常：{}", clientProperties.getHost(),  url, e);
			return new SecretClientResponse<T>(SecretClientHttpErrorCode.OPERATION_ERROR, e.getMessage());
		}
    }
	
    private Map<String, String> getHeaderMap(String body) {
        Map<String, String> hashMap = new HashMap<>();
        hashMap.put("accessKey", clientProperties.getAppId());
        hashMap.put("token", clientProperties.getToken());
        hashMap.put("nonce", RandomUtil.randomNumbers(4));
        String encodedBody = SecureUtil.md5(body);
        hashMap.put("body", encodedBody);
        hashMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        hashMap.put("sign", genSign(encodedBody, clientProperties.getAppSecret()));
        return hashMap;
    }
    
    private static String genSign(String body, String secretKey) {
        Digester md5 = new Digester(DigestAlgorithm.SHA256);
        String content = body + "." + secretKey;
        return md5.digestHex(content);
    }
    
    private void login(String url , Object obj, TypeReference<SecretClientResponse<T>> typeReference) {
		if(clientProperties.isEnable()) {
			SecretClientHttp<String> clientRequest = new SecretClientHttp<String>(clientProperties);
			Map<String, Object> form = new SecretReqBaseForm<Object>()
					.appId(clientProperties.getAppId())
					.add("username", clientProperties.getAppId())
					.add("password", clientProperties.getAppSecret());
			SecretClientResponse<String>  res = clientRequest.execute(SecretReqUrl.AUTH_URL, form);
			if(res.getStatus() == SecretClientHttpErrorCode.SUCCESS) {
				clientProperties.setToken(res.getData());
				retryLoginCount = 0;
				logger.info("secret sdk 登录成功");
				execute(url, obj, typeReference);
			}else {
				logger.error("secret sdk 登录失败：{}", res.getData());
			}
		}
	}
}
